<!--  

This is a prototype for a STPA Step 2 visualization tool

Copyright (c) 2012 Complex Systems Research Lab at MIT (Author: Mario Bernhart)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">

<head>
<title>STPA step 2</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<link rel="stylesheet" href="stpa-step2.css" type="text/css" media="all" />
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/base/jquery-ui.css"/>

<script src="./scripts/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="./scripts/jquery-ui.min.js" type="text/javascript"></script>

<script type="text/javascript"> 

var UCA="";

$.get('./data/UCA.csv', function(data) {
   UCA = data;
}, dataType='text');

var cause="";

$.get('./data/cause.csv', function(data) {
   cause = data;
}, dataType='text');

var controlLoop="";

$.get('./data/control1.uxf', function(data2) {
   controlLoop = data2;
   // console.log(new XMLSerializer().serializeToString(controlLoop));
}, dataType='xml');

var hazard="";

$.get('./data/hazard.csv', function(data) {
	hazard=data;
	}, dataType='text');

// global constants for the element offsets
var xoffset;
var yoffset;

//this main function loads the switch button and hazards from csv, calculates offsets, and draws UCA 1
$(document).ready(function() {

//code for the the show/hide panel button
$("#collapse").click(function() {
    var $marginLefty = $(".menu");
    $marginLefty.animate({
      marginRight: parseInt($marginLefty.css("marginRight"),10) == 0 ?
        -$marginLefty.outerWidth() :
        0
        });
    });
    
//function that styles the buttons inside the "controlbuttons" div
stylebuttons = function(){
	//sets up a numbuttons variable for how many buttons there are 
	var numbuttons = $(".controlswitch").length;
	//changes the css value of each button to position them
	var counter = 0;
	//iterates through all buttons (all have class of controlswitch)
	$(".controlswitch").each(function(){
	//edits the marginLeft property to be a percentage of 80 percent of the menu
		this.style.marginLeft = (counter/numbuttons)*80 + '%';
			console.log(counter);
			counter++;
			});
	};

//runs the stylebuttons function
stylebuttons();
		
//code for the buttons that switch the graphs
$(".controlswitch").click(function() {
	//change the image
	$("#controlstructure").empty();
	//creates the variable for the image file path based on which button is clicked
	var source = 'data/' + String($(this).attr('id')) + '.svg';
	//function that returns the image file path
	getImageSource=function(){
		return source};
	//inserts a new image without a source
	$("#controlstructure").append('<img id="image" src="" alt="some_text"/>');
	//changes the src of the image to the new image
	document.getElementById("image").src = getImageSource();
	//creates the variable for the data file path
	var source2 = 'data/' + String($(this).attr('id')) + '.uxf';
	//function that returns the data file path
	getDataSource=function(){
		return source2};
	//gets the new data
	$.get(getDataSource(), function(data2) {
   		controlLoop = data2;
   		//for some reason putting offset calculation and drawing the UCAS into
   		//this get function works better than having it right afterwards.
   		xoffset=calcOffsets(controlLoop, UCA, hazard)[0];
		yoffset=calcOffsets(controlLoop, UCA, hazard)[1];
		drawUCAS("1");
   		//console.log(new XMLSerializer().serializeToString(controlLoop));
			}, dataType='xml');		
	});
	
//loads hazards, calculates offsets, and draws UCAS (for the initial structure)
loadHazards(hazard);
xoffset=calcOffsets(controlLoop, UCA, hazard)[0];
yoffset=calcOffsets(controlLoop, UCA, hazard)[1];
drawUCAS("1");
insertHazard("1");

//end of ready function
});

/* Draw UCAs from a specific hazard */
function drawUCAS(hazardID) {
$("div[data-type^='UCA']").remove();
$("div[data-type^='cause']").remove();
$("div[data-type^='scenario']").remove();
    	var allUCA = UCA.match(/^.*([\n\r]+|$)/gm);
    	var UCAheader = allUCA[0].split(';');
    //horoffset adds space for the UCAs to be drawn to the left
	horoffset = new Object();
	//vertoffset object is used for making additional UCA rows
	vertoffset = new Object();
	//iterates through all UCAs
    	for (var i=1; i<allUCA.length; i++) {
        	var currentUCA = allUCA[i].split(';');
        			
		if (currentUCA.length == UCAheader.length && searchStringInArray (currentUCA[1].split(','), hazardID) > -1) {	
			
			$('element', controlLoop).each(function()
			{
				if ($(this).find("panel_attributes").text().search(currentUCA[4].trim()) != -1) {
					//variable stores the controller each UCA is associated with
					var name=currentUCA[4];
					//creates horoffset[name] attribute if none exists, sets it to 0
					if (!horoffset[name]) { horoffset[name]=0;}
					//creates name attribute for vertoffset object if none exists, sets it to 0
					if (!vertoffset[name]) { vertoffset[name]=0;}
					// coordinates for the element
					var x = $(this).find("coordinates").find("x").text() * 1 + xoffset - (((horoffset[name]%5)+1) * 30);
					var y = $(this).find("coordinates").find("y").text() * 1 + yoffset + (vertoffset[name]*30);
					var w = 20;
					var h = 20;
					//increases horoffset by 1 each time
					horoffset[name]++;
					//adds new row if horoffset is a multiple of 5
					if (horoffset[name] % 5 == 0) {vertoffset[name]++;}
					
										
					

					// add UCA item
					$("<div/>", {
  						"style": "font-family:arial; text-align: center; position:absolute; top: "+y+"px; left: "+x+"px; background: #FA7C00; background-image:url(./images/"+ currentUCA[2].trim() + ".png); background-size: cover; width: "+w+"px; height: "+h+"px; padding:2px; border: 1px solid black",
  						"title":  currentUCA[3].trim(),
  						"class": "test",
  						"id":  currentUCA[0].trim(),
  						"data-type": "UCA", 
  						"data-param1": currentUCA[0].trim(),
  						"data-param3": currentUCA[2].trim(),
 						"click": function()
 								{
 						 			// reset the background of all UCAs
 						 			jQuery.each($("div[data-type='UCA']"),function() {
 						 				// highlight the selected UCA
      									this.style.backgroundColor = '#FA7C00';
   									});
 						 			this.style.backgroundColor = 'yellow';
									removeAllScenarios();
 						 			findCauses($(this).attr('data-param1'));
									var ucatitle=$(this).attr('title');
									insertUCA(ucatitle);
									insertCauses("");
  								},
  						
  						// open the UCA text on doubleclick
  						"dblclick": function()
  									{
 						 				$('<div></div>')
										.html($(this).attr('title'))
										.dialog({autoOpen: true, title: "UCA " + $(this).attr('data-param1') + " (" + $(this).attr('data-param3') +")"});
									}

  					}).appendTo("body");
					
					// coordinates for the UCA highlight
					x = $(this).find("coordinates").find("x").text() * 1 + xoffset;
					y = $(this).find("coordinates").find("y").text() * 1 + yoffset;
					w = $(this).find("coordinates").find("w").text();
					h = $(this).find("coordinates").find("h").text();
					
					// add UCA highlight
					$("<div/>", {
						"data-type": "UCA-highlight",
  						"style": " font-family:arial; position:absolute; top: "+y+"px; left: "+x+"px; width: "+w+"px; height: "+h+"px; border: 2px solid #FA7C00",
  						"id":  "H" + currentUCA[0].trim()
  					}).appendTo("body");
				
				}
			});
		}
    }
}

function findCauses(forUCA) {
	removeAllCauses();
	var allCauses = cause.match(/^.*([\n\r]+|$)/gm);
    	var CauseHeader = allCauses[0].split(';');
	offset = new Object();
	for (var i=1; i<allCauses.length; i++) {
        var currentCause = allCauses[i].split(';');
		if (currentCause.length == CauseHeader.length && searchStringInArray (currentCause[3].split(','), forUCA) > -1) {
			$('element', controlLoop).each(function() {
				if ($(this).find("panel_attributes").text().search(currentCause[6].trim()) != -1) {
					var name = currentCause[6];
					if (!offset[name]) {offset[name]=0;}
					// coordinates for the UCA element
					var x = $(this).find("coordinates").find("x").text() * 1 + xoffset +  $(this).find("coordinates").find("w").text() * 1 + 8 + ((offset[name]) * 30);
					var y = $(this).find("coordinates").find("y").text() * 1 + yoffset ;
					var w = 20;
					var h = 20;
					offset[name]++;

					// add Cause item
					$("<div/>", {
  						"style": "font-family:arial; text-align: center; background: red; background-image:url(./images/cause.png); background-size:cover; position:absolute; top: "+y+"px; left: "+x+"px;  width: "+w+"px; height: "+h+"px; padding:2px; border: 1px solid black",
  						"title":  currentCause[1].trim(),
  						"id":  currentCause[0].trim(),
  						"data-type": "cause",
  						"data-param1": currentCause[0].trim(),
  						"data-scenario": currentCause[5].trim(),
						  //text:  currentCause[0].trim(),
 						"click": function(){
 						 			// reset the background of all Causes
 						 			jQuery.each($("div[data-type='cause']"),function()
 						 			{
 						 				// reset all causes
      									this.style.backgroundColor = 'red';
   									});
   									// highlight the selected cause
 						 			this.style.backgroundColor = 'yellow';
 						 			hightlightScenario($(this).attr('data-scenario').split(','));
									var causetitle=$(this).attr('title');
									insertCauses(causetitle);
  								},
  						// open the UCA text on doubleclick
  						"dblclick": function()
  									{
 						 				$('<div></div>')
										.html($(this).attr('title'))
										.dialog({autoOpen: true, title: "Cause " + 					$(this).attr('data-param1')});
									}		
  					}).appendTo("body");
					
					// coordinates for the cause highlight
					x = $(this).find("coordinates").find("x").text() * 1 + xoffset;
					y = $(this).find("coordinates").find("y").text() * 1 + yoffset;
					w = $(this).find("coordinates").find("w").text();
					h = $(this).find("coordinates").find("h").text();
					
					// add Cause highlight
					$("<div/>", {
						"data-type" : "cause-highlight",
  						"style": " font-family:arial; position:absolute; top: "+y+"px; left: "+x+"px; width: "+w+"px; height: "+h+"px; border: 2px solid red",
  						"id":  "H" + currentCause[0].trim()
  					}).appendTo("body");
				
				}
			});
		}
	}
};

function hightlightScenario(scenarios) {
	removeAllScenarios();
	console.log(scenarios);

			$('element', controlLoop).each(function()
			{
				if (searchStringInArray(scenarios, $(this).find("panel_attributes").text().trim()) != -1) {

					// coordinates for the scenario highlight
					x = $(this).find("coordinates").find("x").text() * 1 + xoffset;
					y = $(this).find("coordinates").find("y").text() * 1 + yoffset;
					w = $(this).find("coordinates").find("w").text();
					h = $(this).find("coordinates").find("h").text();
					
					// add Scenario highlight
					$("<div/>", {
  						"style": "font-family:arial; position:absolute; top: "+y+"px; left: "+x+"px; width: "+w+"px; height: "+h+"px; background:yellow; opacity:0.4;",
  						"data-type":  "scenario"
  					}).appendTo("body");
				}
			});
};

// This function loads hazards from the hazard.csv data file into the 'select' html element
function loadHazards(data) {
	var allHazard=data.match(/^.*([\n\r]+|$)/gm);
	var hazardHeader=allHazard[0].split(';');
	for (var i=1;i<allHazard.length-1;i++) {
		var currentHazard=allHazard[i].split(';');
		$("<option/>", {"text":currentHazard[1].trim(), "value":currentHazard[0].trim()}).appendTo("select");
	}
}


//this function calculates offsets by looping through three different data files (hazard, control, UCA)
function calcOffsets(uxf, csv, hazard) {
	var xspace=0;
	var yspace=0;
	$("element", uxf).each(function() {
		var allHazard=hazard.match(/^.*([\n\r]+|$)/gm);
		var co=$(this).find("coordinates");
		var allUCA=csv.match(/^.*([\n\r]+|$)/gm);
		for (var j=1;j<allHazard.length-1;j++) {
			var currentHazard=allHazard[j].split(";");
			//if the leftmost element is less than 5 UCAs away from the edge of the screen, the picture/data offset is pushed right by 5 UCAs
			if (co.find("x").text()*1-30*5<xspace) {xspace=co.find("x").text()*1-30*5; }
			if (yspace==0 || co.find("y").text()*1<yspace) { yspace=co.find("y").text()*1; }
		}
	});
	//moves the picture
	$("#image").css("margin-top",(-41+yspace)+"px");
	$("#image").css("margin-left",(-xspace)+"px");
	return [25-xspace,5+yspace];//array for x and y offset
}
	
	
/* This is a helper function to extract a variable from the URL */
function getURLParameter(name) {
	return decodeURIComponent(
        (location.search.match(RegExp("[?|&]"+name+'=(.+?)(&|$)'))||[,null])[1]);
};

/* This is a helper function to search for a string in an string-array */
function searchStringInArray (stringArray, search) {
    for (var j=0; j<stringArray.length; j++) {
        if (stringArray[j].match (search)) return j;
    }
    return -1;
};

// //Removes hazard from sidebar
// function removeDivHazard() {
// 	$("#hazard").empty();
// }

//Removes UCA from sidebar
function removeDivUCA() {
	$("#UCA").empty();
}

//Removes causes from sidebar
function removeDivCauses() {
	$("#cause").empty();
}

/* Removes all causes */
function removeAllCauses () {
   	$('div').remove("div[data-type^='cause']");
}

// //Inserts hazard into sidebar
// function insertHazard(str) {
// 	removeDivHazard();
// 	$("<h2/>", {"text":"Hazard"}).appendTo($("#hazard"));
// 	$("#hazard").append("<hr/>");
// 	var allHazard=hazard.match(/^.*([\n\r]+|$)/gm);
// 	$("<div/>",{"text":((allHazard[str*1].split(";"))[1]).trim()}).appendTo($("#hazard"));
// }

//Inserts UCA into sidebar
function insertUCA(title) {
	removeDivUCA();
	$("<h2/>", {"text":"UCA"}).appendTo($("#UCA"));
        $("#UCA").append("<hr/>");
	$("<div/>",{"text":title}).appendTo($("#UCA"));

}

//Inserts causes into sidebar
function insertCauses(title) {
	removeDivCauses();
	$("<h2/>", {"text":"Cause"}).appendTo($("#cause"));
        $("#cause").append("<hr/>");
        $("<div/>",{"text":title}).appendTo($("#cause"));
}

/* Removes all scenarios */
function removeAllScenarios () {
   	$('div').remove("div[data-type^='scenario']");
}


</script>

</head>

<body>

	
	<br>
	
<!-- Background image of control structure --!>
<div id="controlstructure"> 
<img id="image" src="data/control1.svg" alt="some_text"/>
</div>

<div class="menu">
			<!--  Draws the buttons to switch between control structures 
			The ID of the button must be the same as the filename of the control
			structure it switches to
			--!>
			
			<div id="Control Structure">
				<h2><b>Control Structure</b></h2>
				

				<div id="control1" class="controlswitch">
				<button>1</button>
				</div>

				<div id="control2" class="controlswitch">
				<button>2</button>
				</div>

				<div id="control3" class="controlswitch">
				<button>3</button>
				</div>
				
				<div id="therapist" class="controlswitch">
				<button>4</button>
				</div>
								
				</div>
	<br/>
	</hr>
	<div id="hazard">
		<h2><b>Hazard</b></h2>
		<hr/>
		Select hazard: 
	<select name="hazards"></select>
	</div>
	<div id="UCA">
		<h2><b>UCA</b></h2>
		<hr/>
	</div>
	<div id="cause">
		<h2><b>Cause</b></h2>
		<hr/>
	</div>
	<div id="legend">
    	<h2><b>Legend</b></h2><hr/>
  		  <img class="uca" src="./images/not_provided.png"/>
   		 	Necessary control action was not provided.<br/>
  		  <img class="uca" src="./images/provided.png"/>
			Unsafe control action was provided.<br/>
   		 <img class="uca" src="./images/soon_late.png"/>
			Necessary control action stopped too soon or too late.<br/>
   		 <img class="uca" src="./images/timing.png"/>
			Necessary control action provided at wrong time.<br/>
		<img class="ucacause" src="./images/cause.png"/>
			Cause of unsafe control action.<br/>
		<br/>
		<span id="redbox">Controller</span> Cause of unsafe control action.<br/><br/>
		<span id="fillbox">Scenario</span> Scenario involved with unsafe control action.
	</div>
</div>


<!-- Draws the button to show/hide the legend -->
<div id="collapse">
<button>Show/Hide Panel</button>
</div>

</body>

<script type="text/javascript">

/* Register the change handler on the select element (prepared for multiselect) */
$("select").change(function () {
	var str = "";
    $("select option:selected").each(function () {
    	str += $(this).attr('value');
    });
	drawUCAS(str);
	insertHazard(str);
	insertCauses("");
	insertUCA("");
	
}).change();

</script>

</html>
